﻿
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;


namespace BoilenEditor.Primitives.Snippets {

    [DebuggerDisplay( "SetMemberGroupData: Count={Members.Count}" )]
    public partial class SetMemberGroupData {

        public SetMemberGroupData( IEnumerable<SetMemberData> members )
            : this( members.OrderBy( m => m.Name, MemberNameComparer.Instance ).ToReadOnlyCollection( ) ) {
            Debug.Assert( this.Members.Count > 0 );
            if( this.Entries.Any( ) )
                this.SharedValue = this.Entries.First( );
        }


        public bool IsSet {
            get {
                return !string.IsNullOrEmpty( this.SharedValue )
                    && this.SharedValueIndex != 0;
            }
        }

        public bool IsEditable {
            get { return this.Members.Any( m => m.IsEditable ); }
        }

        public int SharedValueIndex {
            get { return this.Entries.IndexOf( this.SharedValue ); }
        }

        public SetMemberData SelectedMember {
            get { return this.Members[this.SelectedMemberIndex]; }
        }

        private IEnumerable<string> Entries {
            get { return this.Members.SelectMany( m => m.Entries ); }
        }


        public StringBuilder AppendTo( StringBuilder sb ) {
            if( this.IsSet ) {
                SetMemberData member;
                if( this.Members.Count == 1 )
                    member = this.Members.Single( );
                else if( this.SharedName.Length == 0 )
                    member = this.Members[this.SelectedMemberIndex];
                else if( this.SharedValueIndex < 0 )
                    member = this.Members[1];
                else
                    member = this.Members[0];

                member.Value = this.SharedValue;
                member.AppendTo( sb );
            }

            return sb;
        }


        partial void SelectedMemberIndexChanged( int oldValue ) {
            OnPropertyChanged( "SelectedMember" );
        }


        private static ReadOnlyCollection<string> GetNames( IEnumerable<SetMemberData> members ) {
            return members.Select( m => m.Name ).ToReadOnlyCollection( );
        }

        private static ReadOnlyCollection<string> GetTypeNames( IEnumerable<SetMemberData> members ) {
            return members.Select( m => m.TypeName ).ToReadOnlyCollection( );
        }

        private static string GetSharedName( IEnumerable<string> names ) {
            return names
                .Aggregate(
                    (string)null,
                    ( last, name ) => name.OrdinalEqual( last ?? name ) ? name : ""
                );
        }

        private static string GetMergedTypeName( IEnumerable<string> typeNames ) {
            return typeNames
                .Distinct( )
                .Aggregate(
                    new StringBuilder( ),
                    ( sb, t ) => sb.Append( sb.Length > 0 ? " | " : "" ).Append( t ),
                    ( sb ) => sb.ToString( )
                );
        }


        private sealed class MemberNameComparer : IComparer<string> {
            public static MemberNameComparer Instance = new MemberNameComparer( );

            public int Compare( string x, string y ) {
                int compare = x.CompareTo( y );
                bool isDefault = x.StartsWith( "Default" );

                return isDefault
                     ? -compare
                     : compare;
            }
        }


    }

}
